package mildware

import (
	"errors"
	"project/pkg/jwt"
	"project/pkg/models"
	"strconv"
	"strings"

	"github.com/gin-gonic/gin"
)

const (
	CtxUserIDKey   = "userId"
	CtxNickNameKey = "nickName"
	CtxIDKey       = "id"
)

// JWTAuthMiddleware 基于JWT的认证中间件
func JWTAuthMiddleware() func(c *gin.Context) {
	return func(c *gin.Context) {
		resp := new(models.RespData)
		// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
		// 这里假设Token放在Header的Authorization中，并使用Bearer开头
		// 这里的具体实现方式要依据你的实际业务情况决定
		authHeader := c.Request.Header.Get("Authorization")
		if authHeader == "" {
			// c.JSON(http.StatusOK, gin.H{
			// 	"code": 2003,
			// 	"msg":  "请求头中auth为空",
			// })
			resp.SendCode(c, models.CodeNeedLogin)
			c.Abort()
			return
		}
		// 按空格分割
		parts := strings.SplitN(authHeader, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			// c.JSON(http.StatusOK, gin.H{
			// 	"code": 2004,
			// 	"msg":  "请求头中auth格式有误",
			// })
			resp.SendCode(c, models.CodeNeedLogin)
			c.Abort()
			return
		}
		// parts[1]是获取到的tokenString，我们使用之前定义好的解析JWT的函数来解析它
		mc, err := jwt.ParseToken(parts[1])
		if err != nil {
			// c.JSON(http.StatusOK, gin.H{
			// 	"code": 2005,
			// 	"msg":  "无效的Token",CodeInvalidToken
			// })
			resp.SendCode(c, models.CodeInvalidToken)
			c.Abort()
			return
		}
		// 将当前请求的userID信息保存到请求的上下文c上
		c.Set(CtxIDKey, mc.ID)
		c.Set(CtxUserIDKey, mc.UserID)
		c.Set(CtxNickNameKey, mc.NickName)
		c.Next() // 后续的处理函数可以用过c.Get(ctxUserIDkey)来获取当前请求的用户信息
	}
}

var ErrorUserNotLogin = errors.New("用户未登录")

// GetCyrrentUserID 获取当前用户的ID
func GetCyrrentUserID(c *gin.Context) (id, userID, nickName string, err error) {
	uid, ok := c.Get(CtxUserIDKey)
	if !ok {
		err = ErrorUserNotLogin
		return
	}
	userID, ok = uid.(string)
	if !ok {
		return
	}
	nick, ok := c.Get(CtxNickNameKey)
	if !ok {
		err = ErrorUserNotLogin
		return
	}
	nickName, ok = nick.(string)
	if !ok {
		return
	}
	ids, ok := c.Get(CtxIDKey)
	if !ok {
		err = ErrorUserNotLogin
		return
	}
	dd, ok := ids.(uint)
	if !ok {
		return
	}
	id = strconv.Itoa(int(dd))
	return
}
